package com.cxyxj.aopannon;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;

@Aspect
@Component
public class TimeAspect {

    private static final String Pattern = "yyyy-MM-dd HH:mm:ss";

    static final String axx = "execution(* com.cxyxj.aopannon.UserController.queryUser(..))";

    @Pointcut(
            "within(com.cxyxj.aopannon..*) && args(*)")
    public void pointcutCommon(){

    }
    @Pointcut(
            "@annotation(com.cxyxj.aopannon.UserController)")
    public void pointcutCommon2(){

    }


    @Before(value = "pointcutCommon()")
    public void before(JoinPoint joinPoint){
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(Pattern);
        String timeStr = now.format(formatter);
        System.out.println("方法执行开始时间：" + timeStr);
    }

    @After("pointcutCommon()")
    public void after(JoinPoint joinPoint){
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(Pattern);
        String timeStr = now.format(formatter);
        System.out.println("方法执行完成时间：" + timeStr);
    }

    /**
     * @param result：需要与 returning 指定的值保存一致，两者需要同时使用！
     *              result参数的类型需要与目标方法的返回值类型保存一致，如果两者不一致则不会执行该通知方法！
     *              如果不确定目标方法返回的类型，则可以使用 Object
     */
    @AfterReturning(value = "pointcutCommon()",returning = "result")
    public void afterReturning(Object result){
        System.out.println("返回通知：afterReturning = " + result);
    }

    /**
     * @param ex：需要与 throwing 指定的值保存一致，两者需要同时使用！
     */
    @AfterThrowing(value = "pointcutCommon()",throwing = "ex")
    public void afterThrowing(Throwable ex){
        if (ex instanceof ArithmeticException) {
            System.out.println("异常通知：afterThrowing");
        }
    }

    @Around("pointcutCommon()")
    public Object around(ProceedingJoinPoint joinPoint){
        System.out.println("环绕通知前：around");
        try {
            //执行下一个流程
            Object proceed = joinPoint.proceed();
            // proceed 目标方法的返回值
            System.out.println("proceed = " + proceed);
            System.out.println("环绕通知后：around");
            return proceed;
        } catch (Throwable throwable) {
            System.out.println("环绕通知执行下一个流程异常：around");
            //return null;
            throw new ArithmeticException();
        }
    }
}
